package com.pioneer.web.stock.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pioneer.common.constant.PurchaseConstants;
import com.pioneer.common.constant.StockConstants;
import com.pioneer.common.exception.CustomException;
import com.pioneer.web.purchase.domain.PurOrder;
import com.pioneer.web.purchase.domain.PurOrderBody;
import com.pioneer.web.purchase.service.IPurOrderService;
import com.pioneer.web.sale.domain.SalOrder;
import com.pioneer.web.sale.domain.SalOrderBody;
import com.pioneer.web.sale.mapper.SalOrderMapper;
import com.pioneer.web.stock.domain.StoInout;
import com.pioneer.web.stock.domain.StoInoutBody;
import com.pioneer.web.stock.mapper.StoInoutBodyMapper;
import com.pioneer.web.stock.mapper.StoInoutMapper;
import com.pioneer.web.stock.service.IStoInoutService;
import com.pioneer.web.stock.service.IStoOnhandService;
import jakarta.annotation.Resource;
import org.apache.ibatis.executor.BatchResult;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * StoInoutServiceImpl
 *
 * @author hlm
 * @date 2025-04-09 14:55:29
 */
@Service
public class StoInoutServiceImpl extends ServiceImpl<StoInoutMapper, StoInout> implements IStoInoutService {

    @Resource
    private IPurOrderService orderService;

    @Resource
    private StoInoutBodyMapper inoutBodyMapper;

    @Resource
    private IStoOnhandService onhandService;

    @Resource
    private SalOrderMapper orderMapper;

    /* ---------------------------------------- 入库管理 BEGIN ---------------------------------------- */
    @Override
    public StoInout getInoutByOrder(Long orderId) {
        // 根据采购订单ID查询采购订单
        PurOrder order = orderService.selectOrderById(orderId);
        // 构建返回的采购入库单
        StoInout inout = new StoInout();
        inout.setSourceId(order.getOrderId());
        inout.setStatus(StockConstants.INOUT_STATUS_NOTIN);
        // 获取采购订单子表信息
        List<PurOrderBody> orderBodyList = order.getOrderBodyList();
        // 构建返回的采购入库单子表
        List<StoInoutBody> inoutBodyList = new ArrayList<>();
        for (PurOrderBody orderBody : orderBodyList) {
            StoInoutBody inoutBody = new StoInoutBody();
            inoutBody.setSourceRowid(orderBody.getOrderBodyId());
            inoutBody.setInventoryId(orderBody.getInventoryId());
            inoutBody.setOrderNumber(orderBody.getPurNumber());
            inoutBodyList.add(inoutBody);
        }
        inout.setInoutBodyList(inoutBodyList);
        return inout;
    }

    @Override
    public StoInout selectInById(Long inoutId) {
        return getBaseMapper().selectInById(inoutId);
    }

    @Override
    public int addIn(StoInout inout) {
        PurOrder order = orderService.selectOrderById(inout.getSourceId());
        if (order == null) {
            throw new CustomException("采购订单不存在，请刷新后重试");
        }
        if (!"2".equals(order.getApproveStatus())) {
            throw new CustomException("采购订单的审批状态有变化，请刷新后重试");
        }
        if (!"0".equals(order.getIsIn())) {
            throw new CustomException("采购订单的是否入库有变化，请刷新后重试");
        }
        // 新增采购入库单
        StoInout addInout = new StoInout();
        addInout.setType(StockConstants.INOUT_TYPE_IN);
        addInout.setInoutCode(genInoutCode());
        addInout.setSourceId(order.getOrderId());
        addInout.setOrderCode(order.getOrderCode());
        addInout.setStatus(StockConstants.INOUT_STATUS_NOTIN);
        boolean ret = save(addInout);
        if (!ret) {
            throw new CustomException("保存采购入库单失败");
        }
        // 采购订单子表信息
        List<PurOrderBody> orderBodyList = order.getOrderBodyList();
        // 提交的采购入库单子信息
        List<StoInoutBody> inoutBodyList = inout.getInoutBodyList();
        // 新增的出入库单子表信息
        List<StoInoutBody> addBodyList = new ArrayList<>();
        for (StoInoutBody inoutBody : inoutBodyList) {
            StoInoutBody addBody = new StoInoutBody();
            addBody.setInoutId(addInout.getInoutId());
            addBody.setStoreId(inoutBody.getStoreId());
            orderBodyList.stream().filter(o -> o.getOrderBodyId().equals(inoutBody.getSourceRowid())).findFirst().ifPresent(o -> {
                addBody.setSourceRowid(o.getOrderBodyId());
                addBody.setInventoryId(o.getInventoryId());
                addBody.setOrderNumber(o.getPurNumber());
            });
            addBodyList.add(addBody);
        }
        if (CollUtil.isEmpty(addBodyList) || orderBodyList.size() != addBodyList.size()) {
            throw new CustomException("传参错误");
        }
        // 修改采购订单：是否入库：入库中
        PurOrder updateOrder = new PurOrder();
        updateOrder.setOrderId(order.getOrderId());
        updateOrder.setIsIn(PurchaseConstants.ORDER_IN_ING);
        orderService.updateById(updateOrder);
        // 批量新增采购入库单子表
        return inoutBodyMapper.insertBatch(addBodyList);
    }

    @Override
    public boolean updateIn(StoInout inout) {
        // 根据采购入库单ID查询采购入库单
        StoInout stoInout = getById(inout.getInoutId());
        if (stoInout == null) {
            throw new CustomException("采购入库单不存在，请刷新后重试");
        }
        if (!StockConstants.INOUT_STATUS_NOTIN.equals(stoInout.getStatus())) {
            throw new CustomException("只有入库状态为未入库的数据才可以修改");
        }
        // 获取提交的采购入库单子表信息
        List<StoInoutBody> inoutBodyList = inout.getInoutBodyList();
        if (CollUtil.isEmpty(inoutBodyList)) {
            throw new CustomException("采购入库单子表信息不能为空");
        }
        for (StoInoutBody inoutBody : inoutBodyList) {
            StoInoutBody updateBody = new StoInoutBody();
            updateBody.setInoutBodyId(inoutBody.getInoutBodyId());
            updateBody.setStoreId(inoutBody.getStoreId());
            int bodyRet = inoutBodyMapper.updateById(updateBody);
            if (bodyRet <= 0) {
                throw new CustomException("修改采购入库单子表失败");
            }
        }
        return true;
    }

    @Override
    public boolean deleteIn(List<Long> list) {
        // 根据采购入库单ID集合查询采购入库单
        List<StoInout> inoutList = listByIds(list);
        if (CollUtil.isEmpty(inoutList)) {
            throw new CustomException("采购入库单不能为空，请至少选择一条");
        }
        // 采购订单集合
        List<PurOrder> updateOrderList = new ArrayList<>();
        for (StoInout inout : inoutList) {
            // 校验入库状态
            if (!StockConstants.INOUT_STATUS_NOTIN.equals(inout.getStatus())) {
                throw new CustomException("只有入库状态为未入库的数据才可以删除");
            }
            // 构建修改的采购订单
            PurOrder updatePurOrder = new PurOrder();
            updatePurOrder.setOrderId(inout.getSourceId());
            updatePurOrder.setIsIn(PurchaseConstants.ORDER_NOT_IN);
            updateOrderList.add(updatePurOrder);
        }
        // 修改采购订单的是否入库：未入库
        boolean orderRet = orderService.updateBatchById(updateOrderList);
        if (!orderRet) {
            throw new CustomException("修改来源单据[采购订单]失败");
        }
        // 删除采购入库单子表信息
        int bodyRet = inoutBodyMapper.deleteBodyById(list);
        if (bodyRet <= 0) {
            throw new CustomException("删除采购入库单子表失败");
        }
        // 删除采购入库单信息
        boolean ret = removeByIds(list);
        if (!ret) {
            throw new CustomException("删除采购入库单失败");
        }
        return true;
    }

    @Override
    public boolean inoutIn(StoInout inout) {
        StoInout stoInout = selectInById(inout.getInoutId());
        if (stoInout == null) {
            throw new CustomException("采购入库单不存在，请刷新后重试");
        }
        if (!StockConstants.INOUT_STATUS_NOTIN.equals(stoInout.getStatus())) {
            throw new CustomException("只有入库状态为未入库的数据才可以入库");
        }
        // 修改采购入库单状态：已入库
        StoInout updateInout = new StoInout();
        updateInout.setInoutId(inout.getInoutId());
        updateInout.setStatus(StockConstants.INOUT_STATUS_IN);
        boolean ret = updateById(updateInout);
        if (!ret) {
            throw new CustomException("入库失败");
        }
        // 修改采购订单是否入库：已入库
        PurOrder updateOrder = new PurOrder();
        updateOrder.setOrderId(stoInout.getSourceId());
        updateOrder.setIsIn(PurchaseConstants.ORDER_IN);
        boolean orderRet = orderService.updateById(updateOrder);
        if (!orderRet) {
            throw new CustomException("入库失败");
        }
        // 更新现存量表
        return onhandService.updateOnhandByInout(stoInout);
    }
    /* ---------------------------------------- 入库管理 END ---------------------------------------- */


    /* ---------------------------------------- 出库管理 BEGIN ---------------------------------------- */

    @Override
    public boolean genInoutByOrder(SalOrder order) {
        // 1.新增销售出库单
        StoInout inout = new StoInout();
        inout.setType(StockConstants.INOUT_TYPE_OUT);
        inout.setInoutCode(genInoutCode());
        inout.setOrderCode(order.getOrderCode());
        inout.setSourceId(order.getOrderId());
        inout.setStatus(StockConstants.INOUT_STATUS_NOTOUT);
        boolean ret = save(inout);
        if (!ret) {
            throw new CustomException("生成销售出库单失败");
        }
        // 2.新增销售出库单子表
        List<StoInoutBody> inoutBodyList = new ArrayList<>();
        List<SalOrderBody> orderBodyList = order.getOrderBodyList();
        orderBodyList.forEach(orderBody -> {
            StoInoutBody inoutBody = new StoInoutBody();
            inoutBody.setInoutId(inout.getInoutId());
            inoutBody.setSourceRowid(orderBody.getOrderBodyId());
            inoutBody.setInventoryId(orderBody.getInventoryId());
            inoutBody.setOrderNumber(orderBody.getOrderNumber());
            inoutBodyList.add(inoutBody);
        });
        int BodyRet = inoutBodyMapper.insertBatch(inoutBodyList);
        if (BodyRet <= 0) {
            throw new CustomException("生成销售出库单子表失败");
        }
        return true;
    }

    @Override
    public boolean delInoutByOrder(SalOrder order) {
        // 根据销售订单ID查询销售出库单  select * from sto_inout where type = '出库' and source_id = ?
        LambdaQueryWrapper<StoInout> query = Wrappers.lambdaQuery();
        query.eq(StoInout::getType, StockConstants.INOUT_TYPE_OUT).eq(StoInout::getSourceId, order.getOrderId());
        StoInout one = getOne(query);
        if (one != null) {
            // 校验出库状态
            if (!StockConstants.INOUT_STATUS_NOTOUT.equals(one.getStatus())) {
                throw new CustomException("下游单据[销售出库单]已出库，不能弃审");
            }
            // 1.删除销售出库单子表 delete from sto_inout_body where inout_id = ?
            LambdaQueryWrapper<StoInoutBody> bodyDelete = Wrappers.lambdaQuery();
            bodyDelete.eq(StoInoutBody::getInoutId, one.getInoutId());
            int bodyRet = inoutBodyMapper.delete(bodyDelete);
            if (bodyRet <= 0) {
                throw new CustomException("删除下游单据[销售出库单子表]失败");
            }
            // 2.删除销售出库单 delete from sto_inout where inout_id = ?
            boolean ret = removeById(one.getInoutId());
            if (!ret) {
                throw new CustomException("删除下游单据[销售出库单]失败");
            }
        }
        return true;
    }

    @Override
    public StoInout selectOutById(Long inoutId) {
        // 方法1
//        // 根据销售出库单ID查询销售出库单
//        StoInout stoInout = getById(inoutId);
//        // 根据销售订单ID查询销售订单
//        SalOrder order = orderMapper.selectById(stoInout.getSourceId());
//        stoInout.setOrderCode(order.getOrderCode() + " - " + order.getOrderName());
//        // 根据销售出库单ID查询销售出库单子表
//        LambdaQueryWrapper<StoInoutBody> bodyQuery = Wrappers.lambdaQuery();
//        bodyQuery.eq(StoInoutBody::getInoutId, inoutId);
//        List<StoInoutBody> inoutBodyList = inoutBodyMapper.selectList(bodyQuery);
//        stoInout.setInoutBodyList(inoutBodyList);
//        return stoInout;

        // 方法2
        return getBaseMapper().selectOutById(inoutId);
    }

    @Override
    public boolean updateOut(StoInout inout) {
        // 根据销售出库单ID重新销售出库单
        StoInout stoInout = getById(inout.getInoutId());
        if (stoInout == null) {
            throw new CustomException("单据不存在，请刷新后重新");
        }
        // 校验出库状态
        if (!StockConstants.INOUT_STATUS_NOTOUT.equals(stoInout.getStatus())) {
            throw new CustomException("只有出库状态为未出库的数据才可以修改");
        }
        // 校验销售出库单子表信息
        List<StoInoutBody> inoutBodyList = inout.getInoutBodyList();
        if (CollUtil.isEmpty(inoutBodyList)) {
            throw new CustomException("销售出库单子表不能为空");
        }
        // 需要修改的销售出库单子表集合
        List<StoInoutBody> updateInoutBodyList = new ArrayList<>();
        for (StoInoutBody inoutBody : inoutBodyList) {
            // 构建销售出库单子表对象
            StoInoutBody updateInoutBody = new StoInoutBody();
            updateInoutBody.setInoutBodyId(inoutBody.getInoutBodyId());
            updateInoutBody.setStoreId(inoutBody.getStoreId());
            // 添加到修改集合
            updateInoutBodyList.add(updateInoutBody);
        }
        // 执行修改： update sto_inout_body set store_id = ? where inout_body_id = ?
        List<BatchResult> results = inoutBodyMapper.updateById(updateInoutBodyList);
        if (CollUtil.isEmpty(results)) {
            throw new CustomException("修改销售出库单子表失败");
        }
        // 返回
        return true;
    }

    @Override
    public boolean inoutOut(StoInout inout) {
        // 根据销售出库单ID查询详情
        StoInout stoInout = selectOutById(inout.getInoutId());
        if (stoInout == null) {
            throw new CustomException("单据不存在，请刷新后重试");
        }
        // 校验出库状态
        if (!StockConstants.INOUT_STATUS_NOTOUT.equals(stoInout.getStatus())) {
            throw new CustomException("只有出库状态为未出库的数据才可以确认出库");
        }
        // 校验仓库信息
        List<StoInoutBody> inoutBodyList = stoInout.getInoutBodyList();
        for (int i = 0; i < inoutBodyList.size(); i++) {
            StoInoutBody inoutBody = inoutBodyList.get(i);
            if (inoutBody.getStoreId() == null) {
                throw new CustomException("第" + (i + 1) + "行仓库不能为空，请选择");
            }
        }
        // 将出库状态由未出库改为已出库 update sto_inout set status = '1' where inout_id = ?
        StoInout updateInout = new StoInout();
        updateInout.setInoutId(inout.getInoutId());
        updateInout.setStatus(StockConstants.INOUT_STATUS_OUT);
        updateById(updateInout);

        // 更新现存量表
        return onhandService.updateOnhandByInout(stoInout);
    }

    /* ---------------------------------------- 出库管理 END ---------------------------------------- */

    private String genInoutCode() {
        // 根据指定格式获取当天字符串
        String today = DateUtil.format(new Date(), "yyyyMMdd");
        // 查询当天最大流水号记录
        String maxCode = getBaseMapper().selectMaxCode(today);
        if (StrUtil.isBlank(maxCode)) {
            // 当天没有流水号，直接返回
            return "INOUT" + today + "0001";
        } else {
            // 截取最后四位
            String oldCode = maxCode.substring(maxCode.length() - 4);
            // 流水号+1并补0
            String newCode = String.format("%04d", Integer.parseInt(oldCode) + 1);
            // 返回新的流水号
            return "INOUT" + today + newCode;
        }
    }
}
